package com.alpha.common.service;

import com.alpha.common.schemas.attributes.Attribute;
import com.alpha.common.schemas.attributes.AttributeRepository;
import com.alpha.common.schemas.attributes.AttributeService;
import com.alpha.core.utils.CollectionUtil;
import com.alpha.service.annotation.DistributedLock;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 字段属性服务扩展
 *
 * @author chenruwan
 * @since 2022-01-01
 */
@Service
@Primary
public class AttributeServiceImpl extends ServiceImpl<AttributeRepository, Attribute> implements AttributeService {
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DistributedLock("attributes")
    public boolean saveOrUpdateBatch(Collection<Attribute> attributes) {
        List<Attribute> exists = super.list();

        Set<String> serviceNames = attributes.stream().map(Attribute::getServiceName).collect(Collectors.toSet());
        for (String serviceName : serviceNames) {
            Set<String> tableNames = attributes.stream()
                    .filter(e -> e.getServiceName().equals(serviceName))
                    .map(Attribute::getTableName).collect(Collectors.toSet());
            for (String tableName : tableNames) {
                handleOneTable(filterTable(attributes, serviceName, tableName),
                        filterTable(exists, serviceName, tableName));
            }
        }
        return true;
    }

    private List<Attribute> filterTable(Collection<Attribute> attributes, String serviceName, String tableName) {
        return attributes.stream()
                .filter(e -> e.getServiceName().equals(serviceName) && e.getTableName().equals(tableName))
                .collect(Collectors.toList());
    }

    private void handleOneTable(List<Attribute> attributes, List<Attribute> exists) {
        for (Attribute attribute : attributes) {
            Attribute found = findByColumn(exists, attribute.getColumnName());
            if (found == null) {
                super.save(attribute);
                continue;
            }
            updateIfChanged(attribute, found);
        }

        List<Long> removedIds = exists.stream()
                .filter(e -> findByColumn(attributes, e.getColumnName()) == null)
                .map(Attribute::getId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(removedIds)) {
            super.removeByIds(removedIds);
        }
    }

    private void updateIfChanged(Attribute attribute, Attribute existed) {
        attribute.setId(existed.getId());
        if (!Objects.equals(attribute.getVisualName(), existed.getVisualName())
                || !Objects.equals(attribute.getColumnType(), existed.getColumnType())
                || !Objects.equals(attribute.getRequired(), existed.getRequired())
                || !Objects.equals(attribute.getExtended(), existed.getExtended())
                || !Objects.equals(attribute.getFormat(), existed.getFormat())) {
            super.updateById(attribute);
        }
    }

    private Attribute findByColumn(List<Attribute> attributes, String columnName) {
        return attributes.stream().filter(e -> e.getColumnName().equals(columnName)).findFirst().orElse(null);
    }
}
